package javacommon.base;

import java.io.IOException;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import javacommon.util.ConvertRegisterHelper;
import javacommon.util.PageRequestFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
import org.tln.modules.utils.ServletUtils;

import com.thoughtworks.xstream.XStream;

import cn.org.rapid_framework.beanutils.BeanUtils;
import cn.org.rapid_framework.page.Page;
import cn.org.rapid_framework.page.PageRequest;

public class BaseSpringController extends MultiActionController{
	
	private MockHttpServletRequest request;
	
	static {
		//注册converters
		ConvertRegisterHelper.registerConverters();
	}
	
	public void copyProperties(Object target,Object source) {
		BeanUtils.copyProperties(target, source);
	}

	public <T> T copyProperties(Class<T> destClass,Object orig) {
		return BeanUtils.copyProperties(destClass, orig);
	}
	
    /**
     * 初始化binder的回调函数.
     *
     * @see MultiActionController#createBinder(HttpServletRequest,Object)
     */
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
    	binder.registerCustomEditor(Short.class, new CustomNumberEditor(Short.class, true));
        binder.registerCustomEditor(Integer.class, new CustomNumberEditor(Integer.class, true));
        binder.registerCustomEditor(Long.class, new CustomNumberEditor(Long.class, true));
        binder.registerCustomEditor(Float.class, new CustomNumberEditor(Float.class, true));
        binder.registerCustomEditor(Double.class, new CustomNumberEditor(Double.class, true));
        binder.registerCustomEditor(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
        binder.registerCustomEditor(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
    }
	
	public ModelAndView toModelAndView(Page page,PageRequest pageRequest) {
		return toModelAndView("",page, pageRequest);
	}
	
	public ModelAndView toModelAndView(String tableId,Page page,PageRequest pageRequest) {
		ModelAndView model = new ModelAndView();
		saveIntoModelAndView(tableId,page,pageRequest,model);
		return model;
	}
	/**
	 * 用于一个页面有多个extremeTable是使用
	 * @param tableId 等于extremeTable的tableId属性
	 */
	public void saveIntoModelAndView(String tableId,Page page,PageRequest pageRequest,ModelAndView model){
		Assert.notNull(tableId,"tableId must be not null");
		Assert.notNull(page,"page must be not null");
		
		model.addObject(tableId+"page", page);
		model.addObject(tableId+"totalRows", new Integer(page.getTotalCount()));
		model.addObject(tableId+"pageRequest", pageRequest);
	}
	
	public PageRequest newPageRequest(HttpServletRequest request,String defaultSortColumns){
		return PageRequestFactory.newPageRequest(request, defaultSortColumns);
    }
	
	/**
	 * 保存消息在request中,messages.jsp会取出来显示此消息
	 */
    protected static void saveMessage(HttpServletRequest request, String message) {
        if (StringUtils.isNotBlank(message)) {
        	List list = getOrCreateRequestAttribute(request, "springMessages",ArrayList.class);
            list.add(message);
        }
    }
    /**
	 * 保存错误消息在request中,messages.jsp会取出来显示此消息
	 */
    protected static void saveError(HttpServletRequest request, String errorMsg) {
        if (StringUtils.isNotBlank(errorMsg)) {
        	List list = getOrCreateRequestAttribute(request, "springErrors",ArrayList.class);
            list.add(errorMsg);
        }
    }
    
	public static <T> T getOrCreateRequestAttribute(HttpServletRequest request, String key,Class<T> clazz) {
		Object value = request.getAttribute(key);
		if(value == null) {
			try {
				value = clazz.newInstance();
			} catch (Exception e) {
				ReflectionUtils.handleReflectionException(e);
			}
			request.setAttribute(key, value);
		}
		return (T)value;
	}
	

	
	protected void jsonPostInit() {
		addJsonHeader();
		request.setMethod(RequestMethod.POST.toString());
	}

	protected void jsonGetInit() {
		addJsonHeader();
		request.setMethod(RequestMethod.GET.toString());
	}

	protected void jsonPutInit() {
		addJsonHeader();
		request.setMethod(RequestMethod.PUT.toString());
	}

	protected String toJson(Object o) throws Exception {
		System.out.println("toJson...............");
		StringWriter sw = new StringWriter();
		ObjectMapper mapper = new ObjectMapper();
		System.out.println("toJson......start.........");
		mapper.writeValue(sw, o);
		System.out.println("toJson.......end......");
		System.out.println("sw--- "+sw.toString());
		return sw.toString();
	}
	
	protected String toXml(Object o)throws Exception{
		XStream xstream = new XStream();
		xstream.autodetectAnnotations(true);
		return xstream.toXML(o);
	}

	private void addJsonHeader() {
		init();
		request.addHeader("Accept", "application/json, text/javascript, */*");
		request.addHeader("Content-Type", "application/json; charset=UTF-8");
	}


	private void addXmlHeader() {
		init();
		request.addHeader("Accept", "application/xml, text/xml, */*");
		request.addHeader("Content-Type", "application/xml; charset=UTF-8");
	}

	private void init() {
		request = new MockHttpServletRequest();
		request.setCharacterEncoding("UTF-8");
		new MockHttpServletResponse();
	}
	
	protected void xmlGetInit() {
		addXmlHeader();
		request.setMethod(RequestMethod.GET.toString());
	}

	protected void xmlPostInit() {
		addXmlHeader();
		request.setMethod(RequestMethod.POST.toString());
	}

	protected void xmlPutInit() {
		addXmlHeader();
		request.setMethod(RequestMethod.PUT.toString());
	}
	
	
	private static ObjectMapper mapper = new ObjectMapper();
	
	//-- header 常量定义 --//
    private static final String HEADER_ENCODING = "encoding";
    private static final String HEADER_NOCACHE = "no-cache";
    private static final String DEFAULT_ENCODING = "UTF-8";
    private static final boolean DEFAULT_NOCACHE = true;
	
	
	//-- 绕过jsp/freemaker直接输出文本的函数 --//
    /**
     * 直接输出内容的简便函数.

     * eg.
     * render("text/plain", "hello", "encoding:GBK");
     * render("text/plain", "hello", "no-cache:false");
     * render("text/plain", "hello", "encoding:GBK", "no-cache:false");
     *
     * @param headers 可变的header数组，目前接受的值为"encoding:"或"no-cache:",默认值分别为UTF-8和true.
     */
    public static void render(HttpServletResponse response, final String contentType, final String content, final String... headers) {
            response = initResponseHeader(response,contentType, headers);
            try {
                    response.getWriter().write(content);
                    response.getWriter().flush();
            } catch (IOException e) {
                    throw new RuntimeException(e.getMessage(), e);
            }
    }

    /**
     * 直接输出文本.
     * @see #render(String, String, String...)
     */
    public static void renderText(HttpServletResponse response, final String text, final String... headers) {
            render(response, ServletUtils.TEXT_TYPE, text, headers);
    }

    /**
     * 直接输出HTML.
     * @see #render(String, String, String...)
     */
    public static void renderHtml(HttpServletResponse response, final String html, final String... headers) {
            render(response, ServletUtils.HTML_TYPE, html, headers);
    }

    /**
     * 直接输出XML.
     * @see #render(String, String, String...)
     */
    public static void renderXml(HttpServletResponse response, final String xml, final String... headers) {
            render(response, ServletUtils.XML_TYPE, xml, headers);
    }

    /**
     * 直接输出JSON.
     *
     * @param jsonString json字符串.
     * @see #render(String, String, String...)
     */
    public static void renderJson(HttpServletResponse response, final String jsonString, final String... headers) {
            render(response,ServletUtils.JSON_TYPE, jsonString, headers);
    }

    /**
     * 直接输出JSON,使用Jackson转换Java对象.
     *
     * @param data 可以是List<POJO>, POJO[], POJO, 也可以Map名值对.
     * @see #render(String, String, String...)
     */
    public static void renderJson(HttpServletResponse response, final Object data, final String... headers) {
            response = initResponseHeader(response, ServletUtils.JSON_TYPE, headers);
            try {
                    mapper.writeValue(response.getWriter(), data);
            } catch (IOException e) {
                    throw new IllegalArgumentException(e);
            }
    }

    /**
     * 直接输出支持跨域Mashup的JSONP.
     *
     * @param callbackName callback函数名.
     * @param object Java对象,可以是List<POJO>, POJO[], POJO ,也可以Map名值对, 将被转化为json字符串.
     */
    public static void renderJsonp(HttpServletResponse response, final String callbackName, final Object object, final String... headers) {
            String jsonString = null;
            try {
                    jsonString = mapper.writeValueAsString(object);
            } catch (IOException e) {
                    throw new IllegalArgumentException(e);
            }

            String result = new StringBuilder().append(callbackName).append("(").append(jsonString).append(");").toString();

            //渲染Content-Type为javascript的返回内容,输出结果为javascript语句, 如callback197("{html:'Hello World!!!'}");
            render(response, ServletUtils.JS_TYPE, result, headers);
    }

    /**
     * 分析并设置contentType与headers.
     */
    private static HttpServletResponse initResponseHeader(HttpServletResponse response, final String contentType, final String... headers) {
            //分析headers参数
            String encoding = DEFAULT_ENCODING;
            boolean noCache = DEFAULT_NOCACHE;
            for (String header : headers) {
                    String headerName = StringUtils.substringBefore(header, ":");
                    String headerValue = StringUtils.substringAfter(header, ":");

                    if (StringUtils.equalsIgnoreCase(headerName, HEADER_ENCODING)) {
                            encoding = headerValue;
                    } else if (StringUtils.equalsIgnoreCase(headerName, HEADER_NOCACHE)) {
                            noCache = Boolean.parseBoolean(headerValue);
                    } else {
                            throw new IllegalArgumentException(headerName + "不是一个合法的header类型");
                    }
            }

            //HttpServletResponse response = ServletActionContext.getResponse();
            //logger.info("response:::   "+response);
            //设置headers参数
            String fullContentType = contentType + ";charset=" + encoding;
            response.setContentType(fullContentType);
            if (noCache) {
                    ServletUtils.setNoCacheHeader(response);
            }

            return response;
    }
	
}
